package mallgoods

import (
	"context"
	"encoding/json"
	"fmt"
	"strconv"

	"mall/common/cachex"
	"mall/common/jwt"
	"mall/common/mqueuex"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/forum/api/internal/lib/shoppingcart"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/product/rpc/productclient"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type AddShoppingCartItemLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewAddShoppingCartItemLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddShoppingCartItemLogic {
	return &AddShoppingCartItemLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *AddShoppingCartItemLogic) AddShoppingCartItem(
	req *types.AddShoppingCartItemReq,
	headers *[]*types.Header,
) (resp *types.BaseMsgResp, err error) {
	userId := jwt.GetUserId(l.ctx)
	if userId == 0 {
		return nil, resultx.NewErrCode(resultx.TOKEN_EXPIRE_ERROR)
	}

	if len(req.Items) == 0 {
		return nil, resultx.NewErrCode(resultx.PRODUCT_VARIATION_ID_REQUIRED)
	}

	var orderId uint64
	if req.OrderId != nil && *req.OrderId > 0 {
		orderId = *req.OrderId
	}

	var stocks []*productclient.ProductVariationStock
	skuIdQtyMap := make(map[uint64]mqueuex.ShoppingCartSpecialMessage)
	for _, v := range req.Items {
		if v.SkuId != nil && v.Quantity != nil && *v.SkuId > 0 && *v.Quantity > 0 {
			if num, ok := skuIdQtyMap[*v.SkuId]; !ok {
				skuIdQtyMap[*v.SkuId] = mqueuex.ShoppingCartSpecialMessage{
					Quantity:  *v.Quantity,
					PostId:    v.PostId,
					InviterId: v.InviterId,
				}
			} else {
				skuIdQtyMap[*v.SkuId] = mqueuex.ShoppingCartSpecialMessage{
					Quantity:  num.Quantity + *v.Quantity,
					PostId:    v.PostId,
					InviterId: v.InviterId,
				}
			}
		}
	}
	for skuId, qty := range skuIdQtyMap {
		stocks = append(stocks, &productclient.ProductVariationStock{
			Id:    skuId,
			Stock: qty.Quantity,
		})
	}

	res, err := l.svcCtx.ProductRpc.CheckAndSubtractStock(l.ctx, &productclient.CheckAndSubtractStockReq{
		Data:      stocks,
		CheckOnly: pointy.GetPointer(uint32(1)),
	})
	if err != nil {
		logx.Errorw("AddShoppingCartItem CheckAndSubtractStock err", logx.Field("detail", err.Error()))
		return nil, resultx.NewErrCode(resultx.ADD_CART_ITEM_FAILED)
	}

	// logrus.Info(fmt.Sprintf("AddShoppingCartItem CheckAndSubtractStock res: %+v", res))
	if len(res.Msg) > 0 {
		logx.Errorw("AddShoppingCartItem CheckAndSubtractStock res err", logx.Field("detail", res.Msg))
		return nil, resultx.NewErrCode(resultx.ADD_CART_ITEM_FAILED)
	}

	shoppingCart := shoppingcart.NewShoppingCart(l.ctx, l.svcCtx, cachex.ForumShoppingCart)
	msgMap := make(map[uint64]mqueuex.ShoppingCartSpecialMessage)
	for skuId, v := range skuIdQtyMap {
		val, err := shoppingCart.Add(strconv.FormatInt(int64(userId), 10), strconv.FormatInt(int64(skuId), 10), int64(v.Quantity))
		if err != nil {
			return nil, err
		}

		if val > 0 {
			msgMap[skuId] = mqueuex.ShoppingCartSpecialMessage{
				Quantity:  uint32(val),
				PostId:    v.PostId,
				InviterId: v.InviterId,
			}
		}
	}

	err = l.createDeferredUpdateShoppingCartTask(msgMap, userId, orderId)
	if err != nil {
		logrus.Info(fmt.Sprintf("AddShoppingCartItem createDeferredUpdateShoppingCartTask err: %+v", err))
		logx.Errorw("AddShoppingCartItem createDeferredUpdateShoppingCartTask err", logx.Field("detail", err.Error()))
	}

	return &types.BaseMsgResp{
		Msg: "添加成功",
	}, nil
}

func (l *AddShoppingCartItemLogic) createDeferredUpdateShoppingCartTask(
	msgMap map[uint64]mqueuex.ShoppingCartSpecialMessage,
	userId uint64,
	orderId uint64,
) error {
	m := mqueuex.DeferredUpdateShoppingCartMessage{
		SkuQtyMap: msgMap,
		UserId:    pointy.GetPointer(userId),
		OrderId:   pointy.GetPointer(orderId),
	}
	body, err := json.Marshal(m)
	if err != nil {
		return err
	}

	return l.svcCtx.KqDeferredUpdateShoppingCartClient.Push(string(body))

	// _, err = l.svcCtx.ProductRpc.Diagnose(l.ctx, &productclient.DiagnoseReq{
	// 	Diagnose: 8,
	// })
	// if err != nil {
	// 	return nil, err
	// }

	// return &types.BaseMsgResp{}, nil
}
